--[[
-- @Author:      feilong
-- @DateTime:    2020-11-13 23:05:48
-- @Description: redis消息的处理
-- @Example:
	local data = g.Message():callService(".redis", "redis_cmd", nil, "get", "num")
	g.Log():debug("redis data", data)


--]]
local skynet = require("skynet")
local redis = require("skynet.db.redis")
local skynet_queue = require("skynet.queue")
local server_config = dofile(skynet.getenv("server_config"))

local table_remove = table.remove
local table_insert = table.insert


local MessageHandler = class("MessageHandler")

---------------------------------------------------------
-- Private
---------------------------------------------------------
function MessageHandler:ctor()
	
	self.skynet_queue_fun = {}
	local conf = server_config.redis
	self.db_info = {
		host = conf.host,
		port = conf.port,
		db = conf.db_id,
		auth = conf.password,
	}
	if self.db_info.auth == "" then 
		self.db_info.auth = nil
	end
	g.Log():debug("__redis_db_info____", self.db_info)
	self.connections = {} --连接池
	self.allocated_connection_num = 0
	self.max_connection_num = 10 

	self:register()
end

--注册本服务里的消息
function MessageHandler:register()
	self.message_dispatch = g.MsgDis()
	self.message_dispatch:register("start", handler(self,self.start))
	self.message_dispatch:register("redis_cmd", handler(self,self.redisCommand))
	self.message_dispatch:register("normal_cmd", handler(self,self.normalCommand))
	self.message_dispatch:register("sync_cmd", handler(self,self.syncCommand))
	self.message_dispatch:registerDefault(handler(self,self.redisCommand))
end

--从连接池里取一个服务
function MessageHandler:getConnect()

    local connections = self.connections
    if #connections > 0 then
        return table_remove(connections)
    end
    while self.allocated_connection_num >= self.max_connection_num do
        --超上限了，唯有空转等了
        g.Log():error('there is no connection for reusing, waiting for one reused connection')
        skynet.sleep(10)
        if #connections > 0 then
            return table_remove(connections)
        end
    end

    local redis_conf = self.db_info
    local ok,ret = xpcall(redis.connect, debug.traceback, redis_conf)
    while not ok do
        g.Log():error('failed to connect redis',ret)
        skynet.sleep(100)   --one second
        ok,ret = xpcall(redis.connect, debug.traceback, redis_conf)
    end

    self.allocated_connection_num = self.allocated_connection_num + 1
    return ret
end


---------------------------------------------------------
-- CMD
---------------------------------------------------------

function MessageHandler:start()
	return true
end

function MessageHandler:normalCommand(cmd, ...)
	-- body	
	local conn = self:getConnect()
	local func = conn[cmd]
    local ok,ret = xpcall(func, debug.traceback, conn, ...)
    while not ok do
        g.Log():error("___发送消息给redis错误___", ret)
        skynet.sleep(100)
        print('send to redis now retry....')
        ok,ret = xpcall(func, debug.traceback, conn, ...)
    end
    --把连接放回池中
	table_insert(self.connections, conn)
    if not ok then
		g.Log():error(ret) 
	end
	-- print("________", ok, ret)
	return ret
end

--redis命令处理
function MessageHandler:redisCommand(sync_id, cmd, ...)
	if sync_id then
		return self:syncCommand(sync_id, cmd, ...)
	end
	return self:normalCommand(cmd, ...)
end

--根据sync_id同步处理(如用户id)
function MessageHandler:syncCommand(sync_id, cmd, ...)
	if not sync_id then
		g.Log():error("___发送消息给redis错误___assigin_id is not__")
		return 
	end
	--按指定id同步执行
	local fun = self.skynet_queue_fun[sync_id]
	if not fun then 
		fun = skynet_queue()
		self.skynet_queue_fun[sync_id] = fun
	end
	local function call_redis(cmd, ...)
		return self:normalCommand(cmd, ...)
	end
	return fun(call_redis, cmd, ...)
end



return MessageHandler